#ifndef CALLBACK_HPP
#define CALLBACK_HPP

#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QList>

#include <iostream>

/** Template qui permet de convertir une instance de QString en un entier (int).
  * La fonction réalise la conversion en entier, puis assigne cette valeur à la
  * classe passée en argument en utilisant la fonction donnée. Cela permet de
  * convertir, assigner et vérifier que tout s'est bien passé en un appel de
  * fonction.
  *
  * @tparam T classe pour laquelle on veut modifier un membre à valeur entière
  * depuis la valeur contenue dans une instance de QString.
  *
  * @param[in] valeurStr instance de QString contenant le nombre à convertir.
  * @param[in] f pointeur sur une fonction membre de la classe passée en
  * argument, qui sera utilisée en cas de succès de la conversion.
  * @param[in,out] instancePtr pointeur sur l'instance de classe qui sera
  * modifiée par l'appel de la fonction \c f.
  * @param[in] message nom de la variable récupérée, utilisée en cas d'échec de
  * la conversion lors de la création du message d'erreur.
  *
  * @return \e true si tout s'est bien passé, \e false sinon.
  */
template< class T >
bool appelleSetInt( const QString& valeurStr, void (T::*f)( const int& ),
                    T* instancePtr, const QString& message )
{
    int valeurEntier;

    bool conversion( true );
    valeurEntier = valeurStr.toInt( &conversion );

    if ( ! conversion )
    {
        std::cerr << "appelleSetInt : Impossible de lire '"
                  << valeurStr . toUtf8() . constData()
                  << "' comme un entier pour "
                  << message . toUtf8() . constData() << std::endl;
        return false;
    }

    (instancePtr ->*f)( valeurEntier );

    return true;
};

/** Template qui permet de convertir une instance de QString en un entier
  * (unsigned).
  * La fonction réalise la conversion en entier, puis assigne cette valeur à la
  * classe passée en argument en utilisant la fonction donnée. Cela permet de
  * convertir, assigner et vérifier que tout s'est bien passé en un appel de
  * fonction.
  *
  * @tparam T classe pour laquelle on veut modifier un membre à valeur entière
  * non signée depuis la valeur contenue dans une instance de QString.
  *
  * @param[in] valeurStr instance de QString contenant le nombre à convertir.
  * @param[in] f pointeur sur une fonction membre de la classe passée en
  * argument, qui sera utilisée en cas de succès de la conversion.
  * @param[in,out] instancePtr pointeur sur l'instance de classe qui sera
  * modifiée par l'appel de la fonction \c f.
  * @param[in] message nom de la variable récupérée, utilisée en cas d'échec de
  * la conversion lors de la création du message d'erreur.
  *
  * @return \e true si tout s'est bien passé, \e false sinon.
  */
template< class T >
bool appelleSetUnsigned( const QString& valeurStr,
                         void (T::*f)( const unsigned& ),
                         T* instancePtr, const QString& message )
{
    unsigned valeurEntier;

    bool conversion( true );
    if ( valeurStr == "-1u" )
        valeurEntier = -1u;
    else
        valeurEntier = valeurStr.toUInt( &conversion );

    if ( ! conversion )
    {
        std::cerr << "appelleSetUnsigned : Impossible de lire '"
                  << valeurStr . toUtf8() . constData()
                  << "' comme un entier positif pour "
                  << message . toUtf8() . constData() << std::endl;
        return false;
    }

    (instancePtr ->*f)( valeurEntier );

    return true;
};

/** Template qui permet de convertir une instance de QString en un entier
  * (ulong).
  * La fonction réalise la conversion en entier, puis assigne cette valeur à la
  * classe passée en argument en utilisant la fonction donnée. Cela permet de
  * convertir, assigner et vérifier que tout s'est bien passé en un appel de
  * fonction.
  *
  * @tparam T classe pour laquelle on veut modifier un membre à valeur entière
  * non signée depuis la valeur contenue dans une instance de QString.
  *
  * @param[in] valeurStr instance de QString contenant le nombre à convertir.
  * @param[in] f pointeur sur une fonction membre de la classe passée en
  * argument, qui sera utilisée en cas de succès de la conversion.
  * @param[in,out] instancePtr pointeur sur l'instance de classe qui sera
  * modifiée par l'appel de la fonction \c f.
  * @param[in] message nom de la variable récupérée, utilisée en cas d'échec de
  * la conversion lors de la création du message d'erreur.
  *
  * @return \e true si tout s'est bien passé, \e false sinon.
  */
template< class T >
bool appelleSetUnsignedLong( const QString& valeurStr,
                             void (T::*f)( const ulong& ),
                             T* instancePtr, const QString& message )
{
    unsigned valeurEntier;

    bool conversion( true );
    if ( valeurStr == "-1u" )
        valeurEntier = -1u;
    else
        valeurEntier = valeurStr.toULong( &conversion );

    if ( ! conversion )
    {
        std::cerr << "appelleSetLong : Impossible de lire '"
                  << valeurStr . toUtf8() . constData()
                  << "' comme un long entier positif pour "
                  << message . toUtf8() . constData() << std::endl;
        return false;
    }

    (instancePtr ->*f)( valeurEntier );

    return true;
};

/** Template qui permet de convertir une instance de QString en un booléen.
  * La fonction réalise la conversion en booléen, puis assigne cette valeur à la
  * classe passée en argument en utilisant la fonction donnée. Cela permet de
  * convertir, assigner et vérifier que tout s'est bien passé en un appel de
  * fonction.
  *
  * @tparam T classe pour laquelle on veut modifier un membre à valeur entière
  * depuis la valeur contenue dans une instance de QString.
  *
  * @param[in] valeurStr instance de QString contenant le nombre à convertir.
  * @param[in] f pointeur sur une fonction membre de la classe passée en
  * argument, qui sera utilisée en cas de succès de la conversion.
  * @param[in,out] instancePtr pointeur sur l'instance de classe qui sera
  * modifiée par l'appel de la fonction \c f.
  * @param[in] message nom de la variable récupérée, utilisée en cas d'échec de
  * la conversion lors de la création du message d'erreur.
  *
  * @return \e true si tout s'est bien passé, \e false sinon.
  */
template< class T >
bool appelleSetBool( const QString& valeurStr, void (T::*f)( const bool& ),
                     T* instancePtr, const QString& message )
{
    bool valeurBool;

    bool conversion( true );
    if ( valeurStr.toLower() == "true" )
        valeurBool = true;
    else if ( valeurStr.toLower() == "false" )
        valeurBool = false;
    else
        conversion = false;

    if ( ! conversion )
    {
        std::cerr << "appelleSetBool : Impossible de lire '"
                  << valeurStr . toUtf8() . constData()
                  << "' comme un entier pour "
                  << message . toUtf8() . constData() << std::endl;
        return false;
    }

    (instancePtr ->*f)( valeurBool );

    return true;
};

/** Template qui permet de convertir une instance de QString en un réel
  * (double).
  * La fonction réalise la conversion en réel, puis assigne cette valeur à la
  * classe passée en argument en utilisant la fonction donnée. Cela permet de
  * convertir, assigner et vérifier que tout s'est bien passé en un appel de
  * fonction.
  *
  * @tparam T classe pour laquelle on veut modifier un membre à valeur réelle
  * depuis la valeur contenue dans une instance de QString.
  *
  * @param[in] valeurStr instance de QString contenant le nombre à convertir.
  * @param[in] f pointeur sur une fonction membre de la classe passée en
  * argument, qui sera utilisée en cas de succès de la conversion.
  * @param[in,out] instancePtr pointeur sur l'instance de classe qui sera
  * modifiée par l'appel de la fonction \c f.
  * @param[in] message nom de la variable récupérée, utilisée en cas d'échec de
  * la conversion lors de la création du message d'erreur.
  *
  * @return \e true si tout s'est bien passé, \e false sinon.
  */
template< class T >
bool appelleSetDouble( const QString& valeurStr,
                       void (T::*f)( const double& ),
                       T* instancePtr, const QString& message )
{
    double valeurDouble;

    bool conversion( true );
    valeurDouble = valeurStr.toDouble( &conversion );

    if ( ! conversion )
    {
        std::cerr << "appelleSetDouble : Impossible de lire '"
                  << valeurStr . toUtf8() . constData()
                  << "' comme un entier positif pour "
                  << message . toUtf8() . constData() << std::endl;
        return false;
    }

    (instancePtr ->*f)( valeurDouble );

    return true;
};

/** Template qui permet de convertir une instance de QString en une liste de
  * nombres entiers (unsigned).
  * La fonction réalise la conversion en entier, puis assigne cette valeur à la
  * classe passée en argument en utilisant la fonction donnée. Cela permet de
  * convertir, assigner et vérifier que tout s'est bien passé en un appel de
  * fonction.
  *
  * @tparam T classe pour laquelle on veut modifier un membre à valeur entière
  * non signée depuis la valeur contenue dans une instance de QString.
  *
  * @param[in] valeurStr instance de QString contenant les nombres à convertir,
  * séparés par des virgules.
  * @param[in] f pointeur sur une fonction membre de la classe passée en
  * argument, qui sera utilisée en cas de succès de la conversion.
  * @param[in,out] instancePtr pointeur sur l'instance de classe qui sera
  * modifiée par l'appel de la fonction \c f.
  * @param[in] message nom de la variable récupérée, utilisée en cas d'échec de
  * la conversion lors de la création du message d'erreur.
  *
  * @return \e true si tout s'est bien passé, \e false sinon.
  */
template< class T >
bool appelleSetListUnsigned( const QString& valeurStr,
                             void (T::*f)( const QList< unsigned >& ),
                             T* instancePtr, const QString& message )
{
    QList< unsigned > valeursEntiers;
    QStringList valeurSimples = valeurStr.split( ",", QString::SkipEmptyParts );

    bool conversion( true );
    foreach ( QString tmp, valeurSimples )
    {
        valeursEntiers << tmp.toUInt( &conversion );
        if ( ! conversion )
        {
            std::cerr << "appelleSetUnsigned : Impossible de lire '"
                      << tmp . toUtf8() . constData()
                      << "' comme un entier positif pour "
                      << message . toUtf8() . constData() << std::endl;
            return false;
        }
    }

    (instancePtr ->*f)( valeursEntiers );

    return true;
};

#endif // CALLBACK_HPP
